#pragma once

#include <memory>
#include "GeometryUtils.h"

class IRenderable;
class WorldObject;
class Ground;
class Water;
enum EGroundType;

typedef std::pair<size_t, size_t> TCell;

HSMODEL_API TCell ConvertTVectorToTCell(const TVector2& i_vector);

enum EWorldEntityTypes
  {
  WE_GRASS,
  WE_WALKWAY,
  WE_WATER,
  WE_TREE,
  WE_FERRIS,
  WE_BALLOONS_SHOP,
  WE_BENCH
  };

class IWorldInfoController
  {
  public:
    virtual bool AvailableForWalking(const std::string& i_name, TVector2 i_point) const = 0;
    virtual double GetHeightForXY(TVector2 i_point) const = 0;
    virtual void SetHumanPosition(const std::string& i_name, TVector3 i_position) = 0;

    virtual bool CanHumanAcquireBalloon(const TVector3& i_position) = 0;

    virtual ~IWorldInfoController() {}
  };

class WorldInfoController : public IWorldInfoController
  {
  public:
    HSMODEL_API WorldInfoController(Ground& i_ground, std::map<std::string, IRenderable*>& i_objects);

    HSMODEL_API double GetHeightForXY(TVector2 i_point) const;
    HSMODEL_API bool AvailableForWalking(const std::string& i_name, TVector2 i_point) const;

    HSMODEL_API void SetHumanPosition(const std::string& i_name, TVector3 i_position);
    HSMODEL_API void DeleteHumanPosition(const std::string& i_name);

    HSMODEL_API bool IsCellFree(TCell cell) const;
    HSMODEL_API WorldObject* GetObjectByPosition(const TVector2& i_position);
    
    HSMODEL_API void UpdateGroundInfo();
    HSMODEL_API void UpdateWaterInfo();
    HSMODEL_API void UpdateInfo(std::map<std::string, IRenderable*>& i_objects);

    /* Removes object info from m_world_entities. Does not change m_object_positions though! */
    HSMODEL_API void RemoveObject(const WorldObject *i_object);

    HSMODEL_API void SetGroundType(const TVector2& i_point, EGroundType i_type);
    HSMODEL_API void AddWater(std::shared_ptr<Water> i_water);
    HSMODEL_API void RemoveWater(std::shared_ptr<Water> i_water);

    HSMODEL_API bool CanHumanAcquireBalloon(const TVector3& i_position);

    HSMODEL_API bool GetEntityOnCell(EWorldEntityTypes& io_result, const TCell& cell) const;

    HSMODEL_API ~WorldInfoController();

	private:
		void _SynchronizeGroundTypesAndWorldEntities(TCell i_cell, EGroundType i_type);
  private:
    Ground& m_ground;
    std::map<const std::string, TCell> m_human_positions;
    std::map<TCell, IRenderable*> m_objects_positions;

    std::map<TCell, EWorldEntityTypes> m_world_entities;
  };